package com.onlyxiahui.common.lib.util.http;

import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.http.HttpEntity;
import org.apache.http.HttpMessage;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

/**
 * 
 * <br>
 * Date 2020-06-18 15:52:31<br>
 * 
 * @author XiaHui [onlovexiahui@qq.com]<br>
 * @since 1.0.0
 */

public class HttpClientAdaptor {

	private CloseableHttpClient httpClient = null;
	private String requestCharset = "UTF-8";
	private String responseCharset = "UTF-8";

	public HttpClientAdaptor() {
		RequestConfig config = RequestConfig.custom().setConnectTimeout(60000).setSocketTimeout(15000).build();
		this.httpClient = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
	}

	public HttpClientAdaptor(CloseableHttpClient httpClient) {
		this.httpClient = httpClient;
	}

	public CloseableHttpClient getHttpClient() {
		return httpClient;
	}

	public void setHttpClient(CloseableHttpClient httpClient) {
		this.httpClient = httpClient;
	}

	public String getRequestCharset() {
		return requestCharset;
	}

	public void setRequestCharset(String requestCharset) {
		this.requestCharset = requestCharset;
	}

	public String getResponseCharset() {
		return responseCharset;
	}

	public void setResponseCharset(String responseCharset) {
		this.responseCharset = responseCharset;
	}

	public boolean isBlank(final CharSequence cs) {
		int strLen;
		if (cs == null || (strLen = cs.length()) == 0) {
			return true;
		}
		for (int i = 0; i < strLen; i++) {
			if (!Character.isWhitespace(cs.charAt(i))) {
				return false;
			}
		}
		return true;
	}

	public boolean isNotBlank(final CharSequence cs) {
		return !isBlank(cs);
	}

	/******************* Get *********************/

	public String doGet(String url) {
		return this.doGet(url, Collections.emptyMap(), Collections.emptyMap(), null, null);
	}

	public String doGet(String url, Map<String, Object> params) {
		return this.doGet(url, Collections.emptyMap(), params, null, null);
	}

	public String doGet(String url, Map<String, Object> params, String requestCharset) {
		return this.doGet(url, Collections.emptyMap(), params, requestCharset, null);
	}

	public String doGet(String url, Map<String, String> headers, Map<String, Object> params) {
		return this.doGet(url, headers, params, null, null);
	}

	public String doGet(String url, Map<String, String> headers, Map<String, Object> params, String requestCharset) {
		return this.doGet(url, headers, params, requestCharset, null);
	}

	public String doGet(
			String url,
			Map<String, String> headers,
			Map<String, Object> params,
			String requestCharset,
			String responseCharset) {
		if (isBlank(url)) {
			return null;
		}
		url = getUrlWithParameters(url, params, requestCharset);
		HttpGet httpGet = new HttpGet(url);
		setHeaders(httpGet, headers);
		return execute(httpGet, responseCharset);
	}

	/******************* Post body *********************/

	public String doPost(String url, String body) {
		return this.doPost(url, Collections.emptyMap(), body, null, null);
	}

	public String doPost(String url, String body, String requestCharset) {
		return this.doPost(url, Collections.emptyMap(), body, requestCharset, null);
	}

	public String doPost(String url, Map<String, String> headers, String body) {
		return this.doPost(url, headers, body, null, null);
	}

	public String doPost(String url, Map<String, String> headers, String body, String requestCharset) {
		return this.doPost(url, headers, body, requestCharset, null);
	}

	public String doPost(
			String url,
			Map<String, String> headers,
			String body,
			String requestCharset,
			String responseCharset) {

		if (isBlank(url)) {
			return null;
		}

		HttpPost httpPost = new HttpPost(url);
		// 配置请求headers
		setHeaders(httpPost, headers);
		// 配置请求参数
		setBody(httpPost, body, requestCharset);
		return execute(httpPost, responseCharset);
	}

	/******************* Post params *********************/
	public String doPost(String url) {
		return this.doPost(url, Collections.emptyMap(), Collections.emptyMap(), null, null);
	}

	public String doPost(String url, Map<String, Object> params) {
		return this.doPost(url, Collections.emptyMap(), params, null, null);
	}

	public String doPost(String url, Map<String, String> headers, Map<String, Object> params) {
		return this.doPost(url, headers, params, null, null);
	}

	public String doPost(String url, Map<String, String> headers, Map<String, Object> params, String requestCharset) {
		return this.doPost(url, headers, params, requestCharset, null);
	}

	public String doPost(String url,
			Map<String, String> headers,
			Map<String, Object> params,
			String requestCharset,
			String responseCharset) {
		HttpPost httpPost = new HttpPost(url);
		// 配置请求headers
		setHeaders(httpPost, headers);
		// 配置请求参数
		setParameters(null, httpPost, params, requestCharset);
		return execute(httpPost, responseCharset);

	}

	public String getUrlWithParameters(String url, Map<String, Object> params, String charset) {
		if (params != null && !params.isEmpty()) {

			if (isBlank(charset)) {
				charset = this.getRequestCharset();
			}

			List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
			for (Map.Entry<String, Object> entry : params.entrySet()) {
				Object value = entry.getValue();
				if (value != null) {
					pairs.add(new BasicNameValuePair(entry.getKey(), value.toString()));
				}
			}

			if (!pairs.isEmpty()) {
				try {
					String s = "?";
					boolean has = url.indexOf(s) > -1;
					url += (has ? "&" : s) + EntityUtils.toString(new UrlEncodedFormEntity(pairs, Charset.forName(charset)));
				} catch (ParseException | IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		return url;
	}

	public void setHeaders(HttpMessage hm, Map<String, String> headers) {
		// 设置header信息
		if (null != hm && headers != null && headers.size() > 0) {
			for (Map.Entry<String, String> entry : headers.entrySet()) {
				hm.addHeader(entry.getKey(), entry.getValue());
			}
		}
	}

	public void setParameters(HttpPost httpPost, Map<String, Object> params, String charset) {
		setParameters(null, httpPost, params, charset);
	}

	public void setParameters(String url, HttpPost httpPost, Map<String, Object> params, String charset) {
		// 配置请求参数
		if (null != httpPost && params != null && params.size() > 0) {
			Map<String, Object> map = getUrlParameters(url, params);
			HttpEntity e = getUrlEncodedFormEntity(map, charset);
			if (null != e) {
				httpPost.setEntity(e);
			}
		}
	}

	public void setBody(HttpPost httpPost, String body, String charset) {
		if (null != body && !body.isEmpty()) {
			if (isBlank(charset)) {
				charset = this.getRequestCharset();
			}
			StringEntity stringEntity = new StringEntity(body, charset);
			httpPost.setEntity(stringEntity);
		}
	}

	public Map<String, Object> getUrlParameters(String url, Map<String, Object> params) {
		Map<String, Object> map = new HashMap<>(256);
		if (null != url) {
			String s = "?";
			boolean has = url.indexOf(s) > -1;
			if (has) {
				String[] array = url.split("[?]");
				if (array.length > 1) {
					String parameterArray = array[1];
					String[] values = parameterArray.split("&");
					for (int i = 0; i < values.length; i++) {
						String value = values[i];
						if (null != value && value.indexOf("=") != -1) {
							String[] parameter = value.split("=");
							if (parameter.length > 1) {
								map.put(parameter[0], parameter[1]);
							}
						}
					}
				}
			}
		}

		if (null != params) {
			map.putAll(params);
		}
		return map;
	}

	public HttpEntity getUrlEncodedFormEntity(Map<String, Object> params, String charset) {
		UrlEncodedFormEntity e = null;
		if (null != params && !params.isEmpty()) {
			if (isBlank(charset)) {
				charset = this.getRequestCharset();
			}
			List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
			for (Map.Entry<String, Object> entry : params.entrySet()) {
				Object value = entry.getValue();
				if (value != null) {
					pairs.add(new BasicNameValuePair(entry.getKey(), value.toString()));
				}
			}
			if (pairs != null && pairs.size() > 0) {
				e = (new UrlEncodedFormEntity(pairs, Charset.forName(charset)));
			}
		}
		return e;
	}

	public HttpEntity getStringEntity(String body, String charset) {
		StringEntity e = null;
		if (isNotBlank(body)) {
			if (isBlank(charset)) {
				charset = this.getRequestCharset();
			}
			e = new StringEntity(body, Charset.forName(charset));
		}
		return e;
	}

	public String execute(HttpUriRequest request, String charset) {
		String result = null;
		CloseableHttpResponse response = null;
		try {
			if (isBlank(charset)) {
				charset = this.getResponseCharset();
			}

			response = httpClient.execute(request);
			if (response == null || response.getStatusLine() == null) {
				return null;
			}

			int statusCode = response.getStatusLine().getStatusCode();

			if (statusCode == HttpStatus.SC_OK) {
				HttpEntity entity = response.getEntity();
				if (entity != null) {
					result = EntityUtils.toString(entity, charset);
					EntityUtils.consume(entity);
				}
			}
//			else {
//				request.abort();
//			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (response != null) {
				try {
					response.close();
				} catch (IOException e) {
				}
			}
		}
		return result;
	}
}
